
#include "dns_decode.h" 
#include <arpa/inet.h>

int getdnsipbyname(unsigned char *buf, dns_res_t *res)   
{   
    unsigned char *qname,*reader;   
    int i , j , stop;   

    struct sockaddr_in a;   
   
    struct RES_RECORD answers[50],auth[50],addit[50];  //the replies from the DNS server   
    struct sockaddr_in dest;   
       
    struct DNS_HEADER *dns = NULL;   
    struct QUESTION   *qinfo = NULL;    
       
    dns = (struct DNS_HEADER*)buf;   
       
    //move ahead of the dns header and the query field   

    #if 0
    printf("\nThe response contains : ");   
    printf("\n %d Questions.",ntohs(dns->q_count));   
    printf("\n %d Answers.",ntohs(dns->ans_count));   
    printf("\n %d Authoritative Servers.",ntohs(dns->auth_count));   
    printf("\n %d Additional records.\n\n",ntohs(dns->add_count));  
    #endif
   
   
    if (!dns->ans_count || ntohs(dns->ans_count) > 50 || ntohs(dns->auth_count) > 50 || ntohs(dns->add_count) > 50)
	    return -1;

    //reading answers   
    stop = 0;   
       
    reader = buf + sizeof(struct DNS_HEADER);
    // get domain
    //strncpy(res->domain, reader, min(strlen(reader), sizeof(res->domain)-1));
    reader += strlen((char *)reader) + 1;
    if (*reader != 0 && *(reader+1) != 1) // type != 'A'
           return -1;

    reader += sizeof(struct QUESTION);

    //read answers  
    for(i = 0; i < ntohs(dns->ans_count); i++)   
    {   
        answers[i].name = ReadName(reader, buf, &stop);   
        reader = reader + stop;   
           
        answers[i].resource = (struct R_DATA*)(reader);   
        reader = reader + sizeof(struct R_DATA);   
       
        if(ntohs(answers[i].resource->type) == 1) //if its an ipv4 address   
        {   
            answers[i].rdata = (unsigned char*)malloc(ntohs(answers[i].resource->data_len)+1);   
               
            for(j=0 ; j<ntohs(answers[i].resource->data_len) ; j++)   
                answers[i].rdata[j]=reader[j];   
               
            answers[i].rdata[ntohs(answers[i].resource->data_len)] = '\0';   
               
            reader = reader + ntohs(answers[i].resource->data_len);   
           
        }   
        else   
        {   
            answers[i].rdata = ReadName(reader,buf,&stop);   
            reader = reader + stop;   
        }   
           
           
    }   

    if (NULL != answers[0].name)
    {
        strncpy(res->domain, (char *)answers[0].name, strlen((char *)answers[0].name));
    }

        
    //print answers   
    for(i = 0; i < ntohs(dns->ans_count); i++)   
    {   
        //printf("\nAnswer : %d",i+1);   
        //printf("Answers Name  :  %s ",answers[i].name);   
               
        if(ntohs(answers[i].resource->type)==1)   //IPv4 address   
        {   
            unsigned long *p;   
            unsigned char *ip;
            
            p = (unsigned long*)answers[i].rdata;   
            a.sin_addr.s_addr=(*p);    //working without ntohl  
            
	        ip = (unsigned char*)&a.sin_addr;
            //printf("has IPv4 address : %d.%d.%d.%d ", ip[0], ip[1], ip[2], ip[3]);   
    	    memcpy(res->ip, ip, 4);

            for(i = 0; i < ntohs(dns->ans_count); i++) 
            {
               // _free(answers[i].name);
               // _free(answers[i].rdata);
            }
    	    return 0;
        }   

        //if(ntohs(answers[i].resource->type)==5)   //Canonical name for an alias   
        //    printf("has alias name : %s",answers[i].rdata);   
                   
        //printf("\n");   
    }  

    
    for(i = 0; i < ntohs(dns->ans_count); i++) 
    {
        //_free(answers[i].name);
        //_free(answers[i].rdata);
    }
    return -1; 



    
       
    //read authorities   
    for(i=0;i<ntohs(dns->auth_count);i++)   
    {   
        auth[i].name=ReadName(reader,buf,&stop);   
        reader+=stop;   
           
        auth[i].resource=(struct R_DATA*)(reader);   
        reader+=sizeof(struct R_DATA);   
       
        auth[i].rdata=ReadName(reader,buf,&stop);   
        reader+=stop;   
    }   
   
    //read additional   
    for(i=0;i<ntohs(dns->add_count);i++)   
    {   
        addit[i].name=ReadName(reader,buf,&stop);   
        reader+=stop;   
           
        addit[i].resource=(struct R_DATA*)(reader);   
        reader+=sizeof(struct R_DATA);   
       
        if(ntohs(addit[i].resource->type)==1)   
        {   
            addit[i].rdata = (unsigned char*)malloc(ntohs(addit[i].resource->data_len));   
            for(j=0;j<ntohs(addit[i].resource->data_len);j++)   
                addit[i].rdata[j]=reader[j];   
   
            addit[i].rdata[ntohs(addit[i].resource->data_len)]='\0';   
            reader+=ntohs(addit[i].resource->data_len);   
           
        }   
        else   
        {   
            addit[i].rdata=ReadName(reader,buf,&stop);   
            reader+=stop;   
        }   
    }   
   
   
   
    //print authorities   
    for(i=0;i<ntohs(dns->auth_count);i++)   
    {   
        //printf("\nAuthorities : %d",i+1);   
        printf("Authorities Name  :  %s ",auth[i].name);   
        if(ntohs(auth[i].resource->type)==2)   
            printf("has authoritative nameserver : %s",auth[i].rdata);   
        printf("\n");   
    }   
   
    //print additional resource records   
    for(i=0;i<ntohs(dns->add_count);i++)   
    {   
        //printf("\nAdditional : %d",i+1);   
        printf("Additional Name  :  %s ",addit[i].name);   
        if(ntohs(addit[i].resource->type)==1)   
        {   
            long *p;   
            p=(long*)addit[i].rdata;   
            a.sin_addr.s_addr=(*p);    //working without ntohl   
            printf("has IPv4 address :  %s",inet_ntoa(a.sin_addr));   
        }   
        printf("\n");   
    }   
   
    return -1;  
}   


#if 0
int getdnsipbyname1(char *buf, dns_res_t *res)   
{   
    unsigned char *qname,*reader;   
    int i , j , stop;   

    struct sockaddr_in a;   
   
    struct RES_RECORD answers[20],auth[20],addit[20];  //the replies from the DNS server   
    struct sockaddr_in dest;   
       
    struct DNS_HEADER *dns = NULL;   
    struct QUESTION   *qinfo = NULL;   
       
    dns=(struct DNS_HEADER*)buf;   
       
    //move ahead of the dns header and the query field   
   
    printf("\nThe response contains : ");   
    printf("\n %d Questions.",ntohs(dns->q_count));   
    printf("\n %d Answers.",ntohs(dns->ans_count));   
    printf("\n %d Authoritative Servers.",ntohs(dns->auth_count));   
    printf("\n %d Additional records.\n\n",ntohs(dns->add_count));   
   
    if (!dns->ans_count)
	return -1;
       
    //reading answers   
    stop = 0;   
       
    reader = buf + sizeof(struct DNS_HEADER);
    // get domain
    //strncpy(res->domain, reader, min(strlen(reader), sizeof(res->domain)-1));
    reader += strlen(reader) + 1;
    if (*reader != 0 && *(reader+1) != 1) // type != 'A'
           return -1;

    reader += sizeof(struct QUESTION);

    //read answers  
    for(i = 0; i < ntohs(dns->ans_count); i++)   
    {   
        answers[i].name = ReadName(reader, buf, &stop);   
        reader = reader + stop;   
           
        answers[i].resource = (struct R_DATA*)(reader);   
        reader = reader + sizeof(struct R_DATA);   
       
        if(ntohs(answers[i].resource->type) == 1) //if its an ipv4 address   
        {   
            answers[i].rdata = (unsigned char*)malloc(ntohs(answers[i].resource->data_len)+1);   
               
            for(j=0 ; j<ntohs(answers[i].resource->data_len) ; j++)   
                answers[i].rdata[j]=reader[j];   
               
            answers[i].rdata[ntohs(answers[i].resource->data_len)] = '\0';   
               
            reader = reader + ntohs(answers[i].resource->data_len);   
           
        }   
        else   
        {   
            answers[i].rdata = ReadName(reader,buf,&stop);   
            reader = reader + stop;   
        }   
           
           
    }   

    if (NULL != answers[0].name)
    {
        strncpy(res->domain, answers[0].name, strlen(answers[0].name));
    }
       
    //read authorities   
    for(i=0;i<ntohs(dns->auth_count);i++)   
    {   
        auth[i].name=ReadName(reader,buf,&stop);   
        reader+=stop;   
           
        auth[i].resource=(struct R_DATA*)(reader);   
        reader+=sizeof(struct R_DATA);   
       
        auth[i].rdata=ReadName(reader,buf,&stop);   
        reader+=stop;   
    }   
   
    //read additional   
    for(i=0;i<ntohs(dns->add_count);i++)   
    {   
        addit[i].name=ReadName(reader,buf,&stop);   
        reader+=stop;   
           
        addit[i].resource=(struct R_DATA*)(reader);   
        reader+=sizeof(struct R_DATA);   
       
        if(ntohs(addit[i].resource->type)==1)   
        {   
            addit[i].rdata = (unsigned char*)malloc(ntohs(addit[i].resource->data_len));   
            for(j=0;j<ntohs(addit[i].resource->data_len);j++)   
                addit[i].rdata[j]=reader[j];   
   
            addit[i].rdata[ntohs(addit[i].resource->data_len)]='\0';   
            reader+=ntohs(addit[i].resource->data_len);   
           
        }   
        else   
        {   
            addit[i].rdata=ReadName(reader,buf,&stop);   
            reader+=stop;   
        }   
    }   
   
       
    //print answers   
    for(i=0;i<ntohs(dns->ans_count);i++)   
    {   
        //printf("\nAnswer : %d",i+1);   
        printf("Answers Name  :  %s ",answers[i].name);   
               
        if(ntohs(answers[i].resource->type)==1)   //IPv4 address   
        {   
            unsigned int *p;   
            unsigned char *ip;
            p=(long*)answers[i].rdata;   
            a.sin_addr.s_addr=(*p);    //working without ntohl   
	        ip = &a.sin_addr;
            printf("has IPv4 address : %d.%d.%d.%d ", ip[0], ip[1], ip[2], ip[3]);   
    	    memcpy(res->ip, ip, 4);
    	    return 0;
        }   

        if(ntohs(answers[i].resource->type)==5)   //Canonical name for an alias   
            printf("has alias name : %s",answers[i].rdata);   
                   
        printf("\n");   
    }  
    return -1; 
   
    //print authorities   
    for(i=0;i<ntohs(dns->auth_count);i++)   
    {   
        //printf("\nAuthorities : %d",i+1);   
        printf("Authorities Name  :  %s ",auth[i].name);   
        if(ntohs(auth[i].resource->type)==2)   
            printf("has authoritative nameserver : %s",auth[i].rdata);   
        printf("\n");   
    }   
   
    //print additional resource records   
    for(i=0;i<ntohs(dns->add_count);i++)   
    {   
        //printf("\nAdditional : %d",i+1);   
        printf("Additional Name  :  %s ",addit[i].name);   
        if(ntohs(addit[i].resource->type)==1)   
        {   
            long *p;   
            p=(long*)addit[i].rdata;   
            a.sin_addr.s_addr=(*p);    //working without ntohl   
            printf("has IPv4 address :  %s",inet_ntoa(a.sin_addr));   
        }   
        printf("\n");   
    }   
   
    return;   
}
#endif
   
unsigned char* ReadName(unsigned char* reader,unsigned char* buffer,int* count)   
{   
    unsigned char *name;   
    unsigned int p=0,jumped=0,offset;   
    int i=0 , j;   
   
    *count = 1;   
    name   = (unsigned char*)malloc(256);   
       
    name[0]='\0';   
   
    //read the names in 3www6google3com format   
    while(*reader!=0)   
    {   
        if(*reader>=192)   
        {   
            offset = (*reader)*256 + *(reader+1) - 49152; //49152 = 11000000 00000000  ;)   
            reader = buffer + offset - 1;   
            jumped = 1;  //we have jumped to another location so counting wont go up!   
        }   
        else    
        {
            name[p++]=*reader;   
            if (p>255)
            {
           	    printf("!!!!!!! Error name = %s \n", name);
		        return name; 
            }
	    }  
        reader=reader+1;   
           
        i++;
        if (i > 100)
        {
            printf("ReadName buffer: %s\n", buffer);
            return name;
        }
        if(jumped==0) *count = *count + 1; //if we havent jumped to another location then we can count up   
    }   
       
    name[p]='\0';    //string complete   
    if(jumped==1) *count = *count + 1;  //number of steps we actually moved forward in the packet   
       
    //now convert 3www6google3com0 to www.google.com   
    for(i=0;i<(int)strlen((const char*)name);i++)   
    {   
        p=name[i];   
        for(j=0;j<(int)p;j++)   
        {   
            name[i]=name[i+1];   
            i=i+1;   
        }   
        name[i]='.';   
    }   
    if (i >= 1)
        name[i-1]='\0';   //remove the last dot   
    else
        name[0] = '\0';
    return name;           
}   
   
   

   
//this will convert www.google.com to 3www6google3com ;got it :)   
void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host)   
{   
    int lock=0 , i;   
       
    strcat((char*)host,".");   
       
    for(i=0;i<(int)strlen((char*)host);i++)   
    {   
        if(host[i]=='.')   
        {   
            *dns++=i-lock;   
            for(;lock<i;lock++)   
            {   
                *dns++=host[lock];   
            }   
            lock++; //or lock=i+1;   
        }   
    }   
    *dns++='\0';   
}   
   


     
int dns_decode()  //do you know what is int main() ?   
{   
    unsigned char hostname[100];   
	unsigned char response[] = {0x52,0xaa,0x81,0x80,0x00,0x01,0x00,0x03,0x00,0x00,0x00,0x00,0x03,0x77,0x77,0x77,
								0x04,0x73,0x69,0x6e,0x61,0x03,0x63,0x6f,0x6d,0x02,0x63,0x6e,0x00,0x00,0x01,0x00,
								0x01,0xc0,0x0c,0x00,0x05,0x00,0x01,0x00,0x00,0x01,0x09,0x00,0x0a,0x07,0x6a,0x75,
								0x70,0x69,0x74,0x65,0x72,0xc0,0x10,0xc0,0x2d,0x00,0x05,0x00,0x01,0x00,0x00,0x0e,
								0x0c,0x00,0x0a,0x07,0x70,0x6f,0x6c,0x61,0x72,0x69,0x73,0xc0,0x10,0xc0,0x43,0x00,
								0x01,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x04,0xca,0x6c,0x21,0x3c};
    dns_res_t res;

    printf("\nInitialising Winsock...");   
 
    printf("Initialised.");   
       
    printf("\nEnter Hostname to Lookup : \n");   
   

    //ngethostbyname(response, &res);   

    printf("finally: res.domain = %s, res.ip =%u.%u.%u.%u", res.domain, res.ip[0], res.ip[1], res.ip[2], res.ip[3]);
       
    return 0;   
}   
   

